package com.czkevin.cif;

import com.czkevin.cif.commands.CIFMainCommand;
import com.czkevin.cif.crafting.RecipeRegister;
import com.czkevin.cif.listeners.CIFBasicListener;
import com.czkevin.cif.listeners.CIFBlockDebuggerListener;
import com.czkevin.cif.listeners.CIFVanillaActionBlockerListener;
import de.tr7zw.nbtapi.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.RecipeChoice;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.LinkedList;
import java.util.List;

public final class CustomItemFramework extends JavaPlugin implements Listener  {

    public static final String NBT_TAG_ENTRY = "CIFData";

    private static CustomItemFramework instance;
    public static CustomItemFramework getInstance() {
        return instance;
    }


    public static boolean debug = false;

    public static CIFItemInstance getCIFDataFromBlock(Block block) {
        if(block == null || block.getType() != Material.SPAWNER) return null;
        CreatureSpawner spawner = (CreatureSpawner) block.getState();
        NBTTileEntity tile = new NBTTileEntity(spawner);
        if(!tile.hasKey("SpawnData")) return null;
        NBTCompound nbtSpawnData = tile.getCompound("SpawnData");
        if(!nbtSpawnData.hasKey(NBT_TAG_ENTRY)) return null;
        return getCIFData(nbtSpawnData.getCompound(NBT_TAG_ENTRY));
    }

    public static void putCIFData(NBTCompound nbtCompound, CIFItem item, NBTCompound data) {
        nbtCompound.setString("Type", item.type());
        nbtCompound.removeKey("Data");
        if(data != null && NBTReflectionUtil.valideCompound(data)) {
            NBTCompound compound = nbtCompound.addCompound("Data");
            compound.mergeCompound(data);
        }
    }

    public static CIFItemInstance getCIFData(NBTCompound nbtCompound) {
        if(nbtCompound == null) return null;
        if(!nbtCompound.hasKey("Type")) return null;
        CIFItem type = ItemRegister.get(nbtCompound.getString("Type"));
        if(type == null) return null;
        NBTCompound data = null;
        if(nbtCompound.hasKey("Data")) {
            final NBTCompound toMerge = nbtCompound.getCompound("Data");
            data = new NBTContainer();
            data.mergeCompound(toMerge);
        }
        return new CIFItemInstance(type, data);
    }

    public void saveData(Block saveTo, CIFItem type, NBTCompound data) {
        CIFItemInstance instance = CustomItemFramework.getCIFDataFromBlock(saveTo);
        if(instance == null || instance.type != type) return;
        NBTTileEntity tile = new NBTTileEntity(saveTo.getState());
        tile.removeKey("SpawnData");
        NBTCompound compound = tile.addCompound("SpawnData");
        putCIFData(compound, type, data);
    }

    public static CIFItemInstance getCIFDataFromItem(ItemStack itemStack) {
        if(itemStack == null || itemStack.getType() == Material.AIR) return null;
        NBTItem nbt = new NBTItem(itemStack);
        if(!nbt.hasNBTData()) return null;
        if(!nbt.hasKey(NBT_TAG_ENTRY)) return null;
        NBTCompound cif = nbt.getCompound(NBT_TAG_ENTRY);
        return getCIFData(cif);
    }

    public static CIFItem getCIFTypeFromItem(ItemStack itemStack) {
        if(itemStack == null) return null;
        NBTItem nbt = new NBTItem(itemStack);
        if(!nbt.hasNBTData()) return null;
        if(!nbt.hasKey(NBT_TAG_ENTRY)) return null;
        return ItemRegister.get(nbt.getCompound(NBT_TAG_ENTRY).getString("Type"));
    }

    public static boolean isCIFItem(ItemStack itemStack) {
        NBTItem nbt = new NBTItem(itemStack);
        if(nbt.hasKey(CustomItemFramework.NBT_TAG_ENTRY)) return true;
        return false;
    }

    public static ItemStack makeCIFItem(CIFItemInstance instance) {
        return makeCIFItem(instance, false);
    }
    public static ItemStack makeCIFItem(CIFItemInstance instance, boolean isBlock) {
        if(instance == null) throw new IllegalArgumentException("Can not makeCIFItem null CIFItem! ");
        return instance.type.generateItemStack(instance, isBlock);
    }


    @Override
    public void onLoad() {
        instance = this;
        getLogger().info("Registering custom items... ");
        ItemRegister.init();
        RecipeRegister.init();
    }

    public static void debug(String str) {
        if(!debug) return;
        instance.getLogger().info(str);
        Bukkit.broadcast(str, "cif.admin");
    }

    @Override
    public void onEnable() {
        getLogger().info("Registering listeners... ");
        getServer().getPluginManager().registerEvents(new CIFBasicListener(), this);
        getServer().getPluginManager().registerEvents(new CIFVanillaActionBlockerListener(), this);
        getServer().getPluginManager().registerEvents(new CIFBlockDebuggerListener(), this);

        getServer().getPluginManager().registerEvents(this, this);

        getLogger().info("Registering commands... ");
        new CIFMainCommand().register(getCommand("cif"));
    }

    @EventHandler
    public void onServerLoaded(ServerLoadEvent event) {
        if(event.getType() != ServerLoadEvent.LoadType.STARTUP) return;
        getLogger().info("Registering vanilla recipes... ");
        registerVanillaRecipes();
    }

    private void registerVanillaRecipes() {
        ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(this, "advanced_crafting_bench"), makeCIFItem(new CIFItemInstance(ItemRegister.get("AdvancedCraftingBench"))));
        List<Material> mat = new LinkedList<>();
        for(Material m : Material.values()) if(m.name().endsWith("_PLANKS")) mat.add(m);
        recipe.shape("ppp", "pip", "pip");
        recipe.setIngredient('i', Material.IRON_BLOCK);
        recipe.setIngredient('p', new RecipeChoice.MaterialChoice(mat));
        getServer().addRecipe(recipe);
    }

}
